﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PerCederberg.Grammatica.Runtime;

namespace SafeScript.MetaModel
{
    public abstract class MemberAttribute : INamed
    {
        public string Name { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="values">Values attached to the attribute</param>
        /// <param name="context">The context (MemberFunction, MemberVariable, ...) to which this attribute belongs</param>
        /// <returns></returns>
        public static MemberAttribute Create(Node node, string name, object[] values, object context, ErrorReport report)
        {
            if (name == "Native")
            {
                if (context is MemberFunction)
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new JSNativeFunctionAttribute() { Name = name, JSCode = values[0] as string };
                }
                if (context is Property)
                {
                    var res = new JSNativePropertyAttribute() { Name = name };
                    Property prop = context as Property;
                    if ( values.Length == 2 && (values[0] is string) && (values[1] is string) && prop.Getter != null && prop.Setter != null )
                    {
                        res.JSGetterCode = values[0] as string;
                        res.JSSetterCode = values[1] as string;
                    }
                    else if ( values.Length == 1 && (values[0] is string) && prop.Getter != null && prop.Setter == null )
                    {
                        res.JSGetterCode = values[0] as string;
                    }
                    else if (values.Length == 1 && (values[0] is string) && prop.Setter != null && prop.Getter == null)
                    {
                        res.JSSetterCode = values[0] as string;
                    }
                    else
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return res;
                }
                if (context is Class)
                {
                    if (values.Length != 0)
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new JSNativeClassAttribute() { Name = name };
                }
                if (context is EnumItem)
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new JSNativeEnumItemAttribute() { Name = name, JSCode = values[0] as string };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }
            else if (name == "NativeMember")
            {
                if (context is MemberFunction && (context as MemberFunction).IsStatic == false )
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new JSNativeFunctionAttribute() { Name = name, JSCode = values[0] as string, IsMember = true };
                }
                if (context is Property && (context as Property).IsStatic == false)
                {
                    var res = new JSNativePropertyAttribute() { Name = name, IsMember = true };
                    Property prop = context as Property;
                    if (values.Length == 1 && (values[0] is string) )
                    {
                        if (prop.Getter != null )
                            res.JSGetterCode = values[0] as string;
                        if (prop.Setter != null)
                            res.JSSetterCode = values[0] as string;
                    }
                    else
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return res;
                }
                if (context is MemberVariable && (context as MemberVariable).IsStatic == false)
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new JSNativeVariableAttribute() { Name = name, JSCode = values[0] as string, IsMember = true };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }
            else if (name == "HTMLClass")
            {
                if (context is Class)
                {
                    if (values.Length != 0)
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new HTMLClassAttribute() { Name = name };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }
            else if (name == "HTMLProperty")
            {
                if (context is Property)
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new HTMLPropertyAttribute() { Name = name, HTMLName = values[0] as string };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }
            else if (name == "HTMLEvent")
            {
                if (context is MemberEvent)
                {
                    if (values.Length != 1 || !(values[0] is string))
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new HTMLEventAttribute() { Name = name, HTMLName = values[0] as string };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }
            else if (name == "WaveState")
            {
                if (context is Property && (context as Property).IsStatic == true)
                {
                    var res = new WaveStatePropertyAttribute() { Name = name };
                    Property prop = context as Property;
                    if (values.Length != 0)
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return res;
                }
                if (context is Class)
                {
                    if (values.Length != 0)
                    {
                        report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongAttributeValues });
                        return null;
                    }
                    return new WaveStateClassAttribute() { Name = name };
                }
                report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.WrongUsageOfAttribute });
                return null;
            }

            report.Add(new ErrorEntry(node) { Info = name, Type = ErrorType.UnknownAttribute });
            return null;
        }
    }

    public class JSNativeFunctionAttribute : MemberAttribute
    {
        public string JSCode { get; set; }
        public bool IsMember = false;
    }

    public class JSNativeVariableAttribute : MemberAttribute
    {
        public string JSCode { get; set; }
        public bool IsMember = false;
    }

    public class JSNativeEnumItemAttribute : MemberAttribute
    {
        public string JSCode { get; set; }
    }

    public class JSNativePropertyAttribute : MemberAttribute
    {
        public string JSGetterCode { get; set; }
        public string JSSetterCode { get; set; }
        public bool IsMember = false;
    }

    public class JSNativeClassAttribute : MemberAttribute
    {
    }

    public class WaveStatePropertyAttribute : MemberAttribute
    {
    }

    public class WaveStateClassAttribute : MemberAttribute
    {
    }

    public class HTMLClassAttribute : MemberAttribute
    {
    }

    public class HTMLEventAttribute : MemberAttribute
    {
        public string HTMLName { get; set; }
    }

    public class HTMLPropertyAttribute : MemberAttribute
    {
        public string HTMLName { get; set; }
    }
}
